package com.zhongbo.java.websocket.service.impl;

import com.zhongbo.java.websocket.dto.MessageRankDto;
import com.zhongbo.java.websocket.model.User;
import com.zhongbo.java.websocket.service.IMessageRankService;
import com.zhongbo.java.websocket.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 说明：
 *
 * @author 钟波dellNotebook
 * @since 2025年03月24日 星期一 14:37:20
 */
@Service
public class MessageRankServiceImpl implements IMessageRankService {

    // 消息排行榜key前缀
    private static final String MESSAGE_RANK_KEY = "chat:message_rank";
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private IUserService userService;

    // 记录用户消息总数
    @Override
    public void addMessageCount(String userId) {
        // incrementScore: 增加有序集合中某个成员的分数。如果成员不存在，则将其添加到有序集合中。
        redisTemplate.opsForZSet().incrementScore(MESSAGE_RANK_KEY, userId, 1);
    }

    // 获取消息排行榜,前10条
    @Override
    public List<MessageRankDto> getMessageRankList() {
        // 获取前10条,消息总数,并且按照总数倒序排序
        List<MessageRankDto> resultList = new ArrayList<>();
        // reverseRangeWithScores: 获取有序集合中指定范围内的成员及其分数，并且是按照分数从高到低的顺序返回（即反向排序）。
        Set<ZSetOperations.TypedTuple<String>> topUserMessage = redisTemplate.opsForZSet().reverseRangeWithScores(MESSAGE_RANK_KEY, 0, 9);
        if(topUserMessage == null) {
            // 没有消息排行信息,直接返回空数据
            return resultList;
        }
        // 记录返回结果的用户id列表, 用户后面批量查询用户名称
        List<String> userIdList = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> topUser : topUserMessage) {
            Double score = topUser.getScore();
            String userId = topUser.getValue();
            userIdList.add(userId);
        }
        List<User> userList = userService.listUserByUserIds(userIdList);
        // 对userList做一个k/v的map映射,方便后面拿去用户名称
        // key: userId, value: User
        Map<String,User> userMap = new HashMap<>();
        for (User user : userList) {
            userMap.put(user.getId(), user);
        }
        // 组装消息数据列表内容
        for (ZSetOperations.TypedTuple<String> topUser : topUserMessage) {
            Double score = topUser.getScore();
            String userId = topUser.getValue();
            User user = userMap.get(userId);
            MessageRankDto messageRankDto = new MessageRankDto();
            // 如果数据库有这个用户, 获取用户名称, 防止程序异常
            if(user!=null){
                messageRankDto.setName(user.getName());
            }
            messageRankDto.setScore(score);
            messageRankDto.setUserId(userId);
            resultList.add(messageRankDto);
        }
        return resultList;
    }
}
